﻿using Bling.DSL;
using Bling.Util;
using System.Collections.Generic;
using System;
using Bling.Core;

namespace Bling.DSL {
  using Bling.NewOps;
  public abstract partial class Eval<EVAL> : Eval, IEval<EVAL> where EVAL : Eval<EVAL> {
    public virtual Func<Eval<EVAL>, Operation<RET, ARG0>,Eval<EVAL>.Info<RET>>
      Lookup<RET, ARG0>(IOperator<RET, ARG0> Op) {
      throw new NotImplementedException();
    }
    public virtual Func<Eval<EVAL>, Operation<RET, ARG0, ARG1>, Eval<EVAL>.Info<RET>>
      Lookup<RET, ARG0, ARG1>(IOperator<RET, ARG0, ARG1> Op) {
      throw new NotImplementedException();
    }
    public virtual Func<Eval<EVAL>, Operation<RET, ARG0, ARG1, ARG2>, Eval<EVAL>.Info<RET>>
      Lookup<RET, ARG0, ARG1, ARG2>(IOperator<RET, ARG0, ARG1, ARG2> Op) {
      throw new NotImplementedException();
    }

  }

  /*
  public abstract partial class NewEval<EVAL> : Eval, INewEval<EVAL> where EVAL : NewEval<EVAL> {
    public abstract Func<NewEval<EVAL>, Operation<RET, ARG0>, NewEval<EVAL>.Info<RET>>
      Lookup<RET, ARG0>(IOperator<RET, ARG0> Op);
    public abstract Func<NewEval<EVAL>, Operation<RET, ARG0, ARG1>, NewEval<EVAL>.Info<RET>>
      Lookup<RET, ARG0, ARG1>(IOperator<RET, ARG0, ARG1> Op);
    public abstract Func<NewEval<EVAL>, Operation<RET, ARG0, ARG1, ARG2>, NewEval<EVAL>.Info<RET>>
      Lookup<RET, ARG0, ARG1, ARG2>(IOperator<RET, ARG0, ARG1, ARG2> Op);
    public abstract object Lookup(object Special);
  }*/
}

namespace Bling.NewOps {
  using Bling.NewVecs;
  //using Bling.EvalCore;

  // operators are centered around brands.
  public interface IOperator {
    Type[] ArgTypes { get; }
  }
  public interface IOperator<RET> : IOperator {
  }

  public interface IBaseOperator<RET, ARG0> : IOperator<RET> { }
  public interface IBaseOperator<RET, ARG0, ARG1> : IBaseOperator<RET, ARG0> { }
  public interface IBaseOperator<RET, ARG0, ARG1, ARG2> : IBaseOperator<RET, ARG0, ARG1> { }
  public interface IOperator<RET, ARG0> : IBaseOperator<RET, ARG0> {
    Expr<RET> Expand(Expr<ARG0> Arg0);
    string Format(Expr<ARG0> Arg0);
    Expr<ARG0> Inverse0(Expr<ARG0> Arg0, Expr<RET> RHS);
  }
  public abstract class Operator<RET, ARG0> : IOperator<RET, ARG0> {
    public virtual Expr<RET> Expand(Expr<ARG0> Arg0) { return null; }
    public virtual string Format(Expr<ARG0> Arg0) {
      return this + "(" + Arg0 + ")";
    }
    public Type[] ArgTypes { get { return new Type[] { typeof(ARG0) }; } }
    public virtual Expr<ARG0> Inverse0(Expr<ARG0> Arg0, Expr<RET> RHS) { return null; }
    public Func<Func<ARG0, RET>> AsFunc { get; private set; }
    public Expr<RET> Make(Expr<ARG0> Arg0) {
      if (Arg0 is Constant<ARG0> && AsFunc() != null) {
        return new Constant<RET>(AsFunc()(((Constant<ARG0>) Arg0).Value));
      }
      return new Operation<RET, ARG0>(this, Arg0);
    }
  }
  public interface IOperator<RET, ARG0, ARG1> : IBaseOperator<RET, ARG0, ARG1> {
    Expr<RET> Expand(Expr<ARG0> Arg0, Expr<ARG1> Arg1);
    string Format(Expr<ARG0> Arg0, Expr<ARG1> Arg1);
    Expr<ARG0> Inverse0(Expr<ARG0> Arg0, Expr<ARG1> Arg1, Expr<RET> RHS);
    Expr<ARG1> Inverse1(Expr<ARG0> Arg0, Expr<ARG1> Arg1, Expr<RET> RHS);
  }
  public abstract class Operator<RET, ARG0, ARG1> : IOperator<RET, ARG0, ARG1> {
    public virtual Expr<RET> Expand(Expr<ARG0> Arg0, Expr<ARG1> Arg1) { return null; }
    public virtual string Format(Expr<ARG0> Arg0, Expr<ARG1> Arg1) {
      return this + "(" + Arg0 + ", " + Arg1 + ")";
    }
    public Type[] ArgTypes { get { return new Type[] { typeof(ARG0), typeof(ARG1) }; } }
    public virtual Expr<ARG0> Inverse0(Expr<ARG0> Arg0, Expr<ARG1> Arg1, Expr<RET> RHS) { return null; }
    public virtual Expr<ARG1> Inverse1(Expr<ARG0> Arg0, Expr<ARG1> Arg1, Expr<RET> RHS) { return null; }

    public Func<Func<ARG0, ARG1, RET>> AsFunc { get; private set; }
    public Expr<RET> Make(Expr<ARG0> Arg0, Expr<ARG1> Arg1) {
      if (Arg0 is Constant<ARG0> && Arg1 is Constant<ARG1> && AsFunc() != null) {
        return new Constant<RET>(AsFunc()(((Constant<ARG0>)Arg0).Value, ((Constant<ARG1>)Arg1).Value));
      }
      return new Operation<RET, ARG0, ARG1>(this, Arg0, Arg1);
    }
  }

  public interface IOperator<RET, ARG0, ARG1, ARG2> : IBaseOperator<RET, ARG0, ARG1, ARG2> {
    string Format(Expr<ARG0> Arg0, Expr<ARG1> Arg1, Expr<ARG2> Arg2);
    Expr<RET> Expand(Expr<ARG0> Arg0, Expr<ARG1> Arg1, Expr<ARG2> Arg2);
    Expr<ARG0> Inverse0(Expr<ARG0> Arg0, Expr<ARG1> Arg1, Expr<ARG2> Arg2, Expr<RET> RHS);
    Expr<ARG1> Inverse1(Expr<ARG0> Arg0, Expr<ARG1> Arg1, Expr<ARG2> Arg2, Expr<RET> RHS);
    Expr<ARG2> Inverse2(Expr<ARG0> Arg0, Expr<ARG1> Arg1, Expr<ARG2> Arg2, Expr<RET> RHS);
  }
  public abstract partial class Operator<RET, ARG0, ARG1, ARG2> : IOperator<RET, ARG0, ARG1, ARG2> {
    public virtual string Format(Expr<ARG0> Arg0, Expr<ARG1> Arg1, Expr<ARG2> Arg2) {
      return this + "(" + Arg0 + ", " + Arg1 + ", " + Arg2 + ")";
    }
    public Type[] ArgTypes { get { return new Type[] { typeof(ARG0), typeof(ARG1), typeof(ARG2) }; } }
    public virtual Expr<RET> Expand(Expr<ARG0> Arg0, Expr<ARG1> Arg1, Expr<ARG2> Arg2) { return null; }
    public virtual Expr<ARG0> Inverse0(Expr<ARG0> Arg0, Expr<ARG1> Arg1, Expr<ARG2> Arg2, Expr<RET> RHS) { return null; }
    public virtual Expr<ARG1> Inverse1(Expr<ARG0> Arg0, Expr<ARG1> Arg1, Expr<ARG2> Arg2, Expr<RET> RHS) { return null; }
    public virtual Expr<ARG2> Inverse2(Expr<ARG0> Arg0, Expr<ARG1> Arg1, Expr<ARG2> Arg2, Expr<RET> RHS) { return null; }

    public Func<Func<ARG0, ARG1, ARG2, RET>> AsFunc { get; private set; }
    public Expr<RET> Make(Expr<ARG0> Arg0, Expr<ARG1> Arg1, Expr<ARG2> Arg2) {
      if (Arg0 is Constant<ARG0> && 
          Arg1 is Constant<ARG1> && 
          Arg2 is Constant<ARG2> && AsFunc() != null) {
        return new Constant<RET>(AsFunc()(((Constant<ARG0>)Arg0).Value, ((Constant<ARG1>)Arg1).Value, ((Constant<ARG2>)Arg2).Value));
      }
      return new Operation<RET, ARG0, ARG1, ARG2>(this, Arg0, Arg1, Arg2);
    }
  }
  public abstract class Operation<RET> : Expr<RET> {
    public abstract IOperator<RET> BaseOp { get; }
    public abstract Expr[] BaseExprs { get; }

    protected override int GetHashCode0() {
      return BaseOp.GetHashCode();
    }
    protected override bool Equals0(Expr<RET> e) {
      return e is Operation<RET> && ((Operation<RET>)e).BaseOp.Equals(BaseOp);
    }
  }
  public abstract class BaseOperation<RET, ARG0> : Operation<RET> {
    public readonly Expr<ARG0> Arg0;
    public BaseOperation(Expr<ARG0> Arg0) { this.Arg0 = Arg0; }
    protected override bool Equals0(Expr<RET> e) {
      return base.Equals0(e) && Arg0.Equals(((BaseOperation<RET,ARG0>) e).Arg0);
    }
    protected override int GetHashCode0() {
      return base.GetHashCode0() + Arg0.GetHashCode();
    }
    public override bool IsConstant {
      get { return Arg0.IsConstant; }
    }
    public override Expr[] BaseExprs { get { return new Expr[] { Arg0 }; } }
  }
  public abstract class BaseOperation<RET, ARG0, ARG1> : BaseOperation<RET, ARG0> {
    public readonly Expr<ARG1> Arg1;
    public BaseOperation(Expr<ARG0> Arg0, Expr<ARG1> Arg1) : base(Arg0) { this.Arg1 = Arg1; }
    protected override bool Equals0(Expr<RET> e) {
      return base.Equals0(e) && Arg1.Equals(((BaseOperation<RET, ARG0, ARG1>)e).Arg1);
    }
    protected override int GetHashCode0() {
      return base.GetHashCode0() + Arg1.GetHashCode();
    }
    public override bool IsConstant {
      get { return base.IsConstant && Arg1.IsConstant; }
    }
    public override Expr[] BaseExprs { get { return new Expr[] { Arg0, Arg1 }; } }
  }
  public abstract class BaseOperation<RET, ARG0, ARG1, ARG2> : BaseOperation<RET, ARG0, ARG1> {
    public readonly Expr<ARG2> Arg2;
    public BaseOperation(Expr<ARG0> Arg0, Expr<ARG1> Arg1, Expr<ARG2> Arg2) : base(Arg0, Arg1) { this.Arg2 = Arg2; }
    protected override bool Equals0(Expr<RET> e) {
      return base.Equals0(e) && Arg2.Equals(((BaseOperation<RET, ARG0, ARG1,ARG2>)e).Arg2);
    }
    protected override int GetHashCode0() {
      return base.GetHashCode0() + Arg2.GetHashCode();
    }
    public override bool IsConstant {
      get { return base.IsConstant && Arg2.IsConstant; }
    }
    public override Expr[] BaseExprs { get { return new Expr[] { Arg0, Arg1, Arg2 }; } }
  }



  public class Operation<RET, ARG0> : BaseOperation<RET, ARG0> {
    public readonly IOperator<RET, ARG0> Op;
    public Operation(IOperator<RET, ARG0> Op, Expr<ARG0> Arg0) : base(Arg0) { this.Op = Op; }
    public override IOperator<RET> BaseOp { get { return Op; } }
    protected override string ToString1() { return Op.Format(Arg0); }
    protected override Eval<EVAL>.Info<RET> Eval<EVAL>(Eval<EVAL> txt) {
      var f = txt.Lookup(Op);
      if (f != null) {
        return f(txt, this);
      } else {
        var expand = (Expr<RET>)Op.Expand(Arg0);
        if (expand != null) return expand.Eval000(txt);
      }
      throw new NotImplementedException();
    }
    public override bool Solve(IAssign P, Expr<RET> RHS) {
      var result = Op.Inverse0(Arg0, RHS);
      // negate would be arg0
      if (result != null && Arg0.Solve(P, result)) return true;
      var expand = Op.Expand(Arg0);
      if (expand != null && expand.Solve(P, RHS)) return true;
      return base.Solve(P, RHS);
    }
  }
  public class Operation<RET, ARG0, ARG1> : BaseOperation<RET, ARG0, ARG1> {
    public readonly IOperator<RET, ARG0, ARG1> Op;
    public Operation(IOperator<RET, ARG0, ARG1> Op, Expr<ARG0> Arg0, Expr<ARG1> Arg1) : base(Arg0, Arg1) { this.Op = Op; }
    public override IOperator<RET> BaseOp { get { return Op; } }
    protected override string ToString1() { return Op.Format(Arg0, Arg1); }
    protected override Eval<EVAL>.Info<RET> Eval<EVAL>(Eval<EVAL> txt) {
      var f = txt.Lookup(Op);
      if (f != null) {
        return f(txt, this);
      } else {
        var expand = (Expr<RET>)Op.Expand(Arg0, Arg1);
        if (expand != null) return expand.Eval000(txt);
      }
      throw new NotImplementedException();
    }
    public override bool Solve(IAssign P, Expr<RET> RHS) {
      var result0 = Op.Inverse0(Arg0, Arg1, RHS);
      // negate would be arg0
      if (result0 != null && Arg0.Solve(P, result0)) return true;
      var result1 = Op.Inverse1(Arg0, Arg1, RHS);
      if (result1 != null && Arg1.Solve(P, result1)) return true;
      var expand = Op.Expand(Arg0, Arg1);
      if (expand != null && expand.Solve(P, RHS)) return true;
      return base.Solve(P, RHS);
    }
  }
  public class Operation<RET, ARG0, ARG1, ARG2> : BaseOperation<RET, ARG0, ARG1,ARG2> {
    public readonly IOperator<RET, ARG0, ARG1, ARG2> Op;
    public Operation(IOperator<RET, ARG0, ARG1, ARG2> Op, Expr<ARG0> Arg0, Expr<ARG1> Arg1, Expr<ARG2> Arg2) : base(Arg0,Arg1,Arg2) { this.Op = Op;  }
    public override IOperator<RET> BaseOp { get { return Op; } }
    protected override string ToString1() {
      return Op.Format(Arg0, Arg1, Arg2);
    }
    protected override Eval<EVAL>.Info<RET> Eval<EVAL>(Eval<EVAL> txt) {
      var f = txt.Lookup(Op);
      if (f != null) {
        return f(txt, this);
      } else {
        var expand = (Expr<RET>)Op.Expand(Arg0, Arg1, Arg2);
        if (expand != null) return expand.Eval000(txt);
      }
      throw new NotImplementedException();
    }
    public override bool Solve(IAssign P, Expr<RET> RHS) {
      var result0 = Op.Inverse0(Arg0, Arg1, Arg2, RHS);
      // negate would be arg0
      if (result0 != null && Arg0.Solve(P, result0)) return true;
      var result1 = Op.Inverse1(Arg0, Arg1, Arg2, RHS);
      if (result1 != null && Arg1.Solve(P, result1)) return true;
      var result2 = Op.Inverse2(Arg0, Arg1, Arg2, RHS);
      if (result2 != null && Arg2.Solve(P, result2)) return true;
      var expand = (Expr<RET>)Op.Expand(Arg0, Arg1, Arg2);
      if (expand != null && expand.Solve(P, RHS)) return true;
      return base.Solve(P, RHS);
    }
  }
}
namespace Bling.NewOps {
  using NewVecs;
  using Conversions;
  public interface IHasId : IOperator {
    string Id { set; get; }
    string Alt { set; get; }
    IOperator Op { set; get; }
  }
  public static class Defined<T> {
    /*
    public static readonly HashSet<IHasId> Math = new HashSet<IHasId>();
    public static readonly HashSet<IHasId> Shader = new HashSet<IHasId>();
    public static readonly HashSet<IHasId> Primitive = new HashSet<IHasId>();
     */
  }
  public static class Defined<T,D> where D : Dim<D> {
    /*
    public static readonly HashSet<IHasId> Math = new HashSet<IHasId>();
    public static readonly HashSet<IHasId> Shader = new HashSet<IHasId>();
    public static readonly HashSet<IHasId> Primitive = new HashSet<IHasId>();
     */
    public static void Add(IHasId Op) {
      /*
      if (Op is IMathDefined) Math.Add(Op);
      if (Op is IPrimitiveDefined) Primitive.Add(Op);
      if (Op is IShaderDefined) Shader.Add(Op);
      if (Op is IMathDefined) Defined<T>.Math.Add(Op);
      if (Op is IPrimitiveDefined) Defined<T>.Primitive.Add(Op);
      if (Op is IShaderDefined) Defined<T>.Shader.Add(Op);
       */
    }
  }

  public interface IMathDefined : IHasId { }
  public interface IShaderDefined : IHasId { }
  public interface IPrimitiveDefined : IHasId { }


  public abstract class UnaryOp<T, S> : Operator<S, T>, IHasId {
    public UnaryOp() {
    }

    public virtual string Id { set; get; }
    public string Alt { set; get; }
    public virtual IOperator Op { set; get; }
    public override Expr<S> Expand(Expr<T> Arg0) {
      if (CustomExpand != null) {
        var result = CustomExpand(Arg0);
        if (((object)result) != null) return result;
      }
      return base.Expand(Arg0);
    }
    public Func<Expr<T>, Expr<S>> CustomExpand {
      private get;
      set;
    }
    public Func<Expr<T>, Expr<S>, Expr<T>> CustomInverse0 {
      private get;
      set;
    }
    public override Expr<T> Inverse0(Expr<T> Arg0, Expr<S> RHS) {
      if (CustomInverse0 != null) return CustomInverse0(Arg0, RHS);
      return base.Inverse0(Arg0, RHS);
    }
    public override string Format(Expr<T> Arg0) {
      return Id + Arg0;
    }
  }
  public abstract class UnaryOp<T, S, D> : UnaryOp<IVec<T, D>, IVec<S, D>> where D : Dim<D> {
    public UnaryOp<T, S, D1> MonoOp { get; set; }
    public override Expr<IVec<S, D>> Expand(Expr<IVec<T, D>> Arg0) {
      var e = base.Expand(Arg0);
      if (e != null || MonoOp == null || Dim<D>.Count == 1) return e;
      var Es = new Expr<S>[Dim<D>.Count];
      for (int i = 0; i < Es.Length; i++) {
        Es[i] = MonoOp.Make(Arg0.Access(i).Bl0()).Access(0);
      }
      return Composite<S, D>.Make(Es);
    }
  }

  public abstract class BinaryOp<T, S, R> : Operator<R, T, S>, IHasId {
    public string Id { set; get; }
    public string Alt { set; get; }
    public virtual IOperator Op { set; get; }
    public BinaryOp() {
    }
    public override Expr<R> Expand(Expr<T> Arg0, Expr<S> Arg1) {
      if (CustomExpand != null) {
        var result = CustomExpand(Arg0, Arg1);
        if (((object)result) != null) return result;
      }
      return base.Expand(Arg0, Arg1);
    }
    public Func<Expr<T>, Expr<S>, Expr<R>> CustomExpand {
      private get;
      set;
    }
    public Func<Expr<T>, Expr<S>, Expr<R>, Expr<T>> CustomInverse0 {
      private get;
      set;
    }
    public Func<Expr<T>, Expr<S>, Expr<R>, Expr<S>> CustomInverse1 {
      private get;
      set;
    }
    public override Expr<T> Inverse0(Expr<T> Arg0, Expr<S> Arg1, Expr<R> RHS) {
      if (CustomInverse0 != null) return CustomInverse0(Arg0, Arg1, RHS);
      return base.Inverse0(Arg0, Arg1, RHS);
    }
    public override Expr<S> Inverse1(Expr<T> Arg0, Expr<S> Arg1, Expr<R> RHS) {
      if (CustomInverse1 != null) return CustomInverse1(Arg0, Arg1, RHS);
      return base.Inverse1(Arg0, Arg1, RHS);
    }
    public override string Format(Expr<T> Arg0, Expr<S> Arg1) {
      return Arg0 + " " + Id + " " + Arg1;
    }
  }
  public abstract class BinaryOp<T, S, R, D> : BinaryOp<IVec<T, D>, S, IVec<R, D>> where D : Dim<D> {
    public Func<int, Expr<T>, Expr<S>, Expr<R>> MonoOp { private get; set; }
    public override Expr<IVec<R, D>> Expand(Expr<IVec<T, D>> Arg0, Expr<S> Arg1) {
      var e = base.Expand(Arg0, Arg1);
      if (e != null || MonoOp == null || Dim<D>.Count == 1) return e;
      var Es = new Expr<R>[Dim<D>.Count];
      for (int i = 0; i < Es.Length; i++) {
        Es[i] = MonoOp(i, Arg0.Access(i), Arg1);
      }
      return Composite<R, D>.Make(Es);
    }
  }
  public abstract class Binary2Op<T, S, R, D> : BinaryOp<T, IVec<S, D>, R, D> where D : Dim<D> {
    private Binary2Op<T, S, R, D1> MonoOp0;
    public new Binary2Op<T, S, R, D1> MonoOp {
      get { return MonoOp0; }
      set {
        MonoOp0 = value;
        base.MonoOp = (i, t, s) => value.Make(t.Bl0(), s.Access(i).Bl0()).Access(0);
      }
    }

    public Func<Expr<IVec<T, D>>, Expr<IVec<S, D>>, Expr<IVec<R, D>>> CustomExpandIfOne {
      set {
        if (Dim<D>.Count == 1) CustomExpand = value;
      }
    }
  }
  public abstract class TrinaryOp<T, S, R, Q> : Operator<Q, T, S, R>, IHasId {
    public string Id { set; get; }
    public string Alt { set; get; }
    public virtual IOperator Op { set; get; }
    public TrinaryOp() {
    }
    public override Expr<Q> Expand(Expr<T> Arg0, Expr<S> Arg1, Expr<R> Arg2) {
      if (CustomExpand != null) {
        var result = CustomExpand(Arg0, Arg1, Arg2);
        if (((object)result) != null) return result;
      }
      return base.Expand(Arg0, Arg1, Arg2);
    }
    public Func<Expr<T>, Expr<S>, Expr<R>, Expr<Q>> CustomExpand {
      private get;
      set;
    }
    public Func<Expr<T>, Expr<S>, Expr<R>, Expr<Q>, Expr<T>> CustomInverse0 {
      private get;
      set;
    }
    public Func<Expr<T>, Expr<S>, Expr<R>, Expr<Q>, Expr<S>> CustomInverse1 {
      private get;
      set;
    }
    public Func<Expr<T>, Expr<S>, Expr<R>, Expr<Q>, Expr<R>> CustomInverse2 {
      private get;
      set;
    }
    public override Expr<T> Inverse0(Expr<T> Arg0, Expr<S> Arg1, Expr<R> Arg2, Expr<Q> RHS) {
      if (CustomInverse0 != null) return CustomInverse0(Arg0, Arg1, Arg2, RHS);
      return base.Inverse0(Arg0, Arg1, Arg2, RHS);
    }
    public override Expr<S> Inverse1(Expr<T> Arg0, Expr<S> Arg1, Expr<R> Arg2, Expr<Q> RHS) {
      if (CustomInverse1 != null) return CustomInverse1(Arg0, Arg1, Arg2, RHS);
      return base.Inverse1(Arg0, Arg1, Arg2, RHS);
    }
    public override Expr<R> Inverse2(Expr<T> Arg0, Expr<S> Arg1, Expr<R> Arg2, Expr<Q> RHS) {
      if (CustomInverse2 != null) return CustomInverse2(Arg0, Arg1, Arg2, RHS);
      return base.Inverse2(Arg0, Arg1, Arg2, RHS);
    }
  }
  public abstract class TrinaryOp<T, S, R, Q, D> : TrinaryOp<IVec<T, D>, IVec<S, D>, IVec<R, D>, IVec<Q, D>> where D : Dim<D> {
    public TrinaryOp<T, S, R, Q, D1> MonoOp { set; get; }
    public override Expr<IVec<Q, D>> Expand(Expr<IVec<T, D>> Arg0, Expr<IVec<S, D>> Arg1, Expr<IVec<R, D>> Arg2) {
      var e = base.Expand(Arg0, Arg1, Arg2);
      if (MonoOp == null || e != null || Dim<D>.Count == 1) return e;
      var Es = new Expr<Q>[Dim<D>.Count];
      for (int i = 0; i < Es.Length; i++) {
        Es[i] = MonoOp.Make(Arg0.Access(i).Bl0(), Arg1.Access(i).Bl0(), Arg2.Access(i).Bl0()).Access(0);
      }
      return Composite<Q, D>.Make(Es);
    }
    public Func<Expr<IVec<T, D>>, Expr<IVec<S, D>>, Expr<IVec<R, D>>, Expr<IVec<Q, D>>> CustomExpandIfOne {
      set {
        if (Dim<D>.Count == 1) base.CustomExpand = value;
      }
    }

  }
}
